﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Threading;
using System.Xml.Linq;
using PengSW.NotifyPropertyChanged;
using PengSW.ObservableCollectionHelper;
using PengSW.XmlHelper;
using static PengSW.RuntimeLog.RL;

namespace PengSW.Schedule
{
    public class ScheduleManager : NotifyPropertyChangedObject, IDisposable, IXmlSeriable
    {
        #region 构造和撤销

        public ScheduleManager(IEnumerable<IScheduleFactory> aFactories, object aContent)
        {
            ScheduleFactories = new ObservableCollectionEx<IScheduleFactory>(aFactories);
            _Content = aContent;
            _Dispatcher = Dispatcher.CurrentDispatcher;
            _Timer = new DispatcherTimer(TimeSpan.FromMilliseconds(1), DispatcherPriority.Send, OnDispatch_Tick, _Dispatcher);
            _Timer.Stop();
        }

        public void Dispose()
        {
            StopDispatch();
            StopAllSchedules();
        }

        #endregion

        #region 序列化

        public XElement CreateXElement(string aXmlNodeName)
        {
            return new XElement(aXmlNodeName, from r in Schedules select r.CreateXElement("Schedule"));
        }

        public void ReadFromXml(XElement aXElement)
        {
            foreach (XElement aScheduleXElement in aXElement.Elements("Schedule"))
            {
                IScheduleFactory aScheduleFactory = (from r in ScheduleFactories where r.IsCreatable(aScheduleXElement) select r).FirstOrDefault();
                if (aScheduleFactory == null)
                    L($"没有找到结点[{aScheduleXElement.ToString(SaveOptions.DisableFormatting)}]的计划任务创建器！");
                else
                {
                    ISchedule aSchedule = aScheduleFactory.CreateSchedule(aScheduleXElement);
                    Schedules.Add(aSchedule);
                }
            }
        }

        #endregion

        #region 状态属性

        public bool IsDispatching { get { return _IsDispatching; } set { SetValue(ref _IsDispatching, value, nameof(IsDispatching)); } }
        private bool _IsDispatching = false;

        #endregion

        #region 计划任务调度和管理

        public ObservableCollectionEx<ISchedule> Schedules { get; } = new ObservableCollectionEx<ISchedule>();
        public ObservableCollectionEx<IScheduleFactory> ScheduleFactories { get; }

        public void AddFactory(IScheduleFactory aFactory)
        {
            if (ScheduleFactories.Contains(aFactory)) return;
            ScheduleFactories.Add(aFactory);
        }

        public void AddFactories(IEnumerable<IScheduleFactory> aFactories)
        {
            foreach (IScheduleFactory aFactory in from r in aFactories where !ScheduleFactories.Contains(r) select r)
                ScheduleFactories.Add(aFactory);
        }

        public void AddSchedule(ISchedule aSchedule)
        {
            L($"新增计划任务[{aSchedule}]……");
            Schedules.Add(aSchedule);
        }

        public void RemoveSchedule(ISchedule aSchedule)
        {
            if (aSchedule == null) return;
            L($"删除计划任务[{aSchedule.Description}]……");
            aSchedule.Stop();
            Schedules.Remove(aSchedule);
        }

        public void StartDispatch()
        {
            if (IsDispatching) return;
            L("开始调度计划任务……");
            _Timer.Start();
            _IsDispatching = true;
        }

        public void StopDispatch()
        {
            if (!IsDispatching) return;
            L($"停止调度计划任务……");
            _Timer.Stop();
            _IsDispatching = false;
        }

        public void StartAllSchedules()
        {
            L("启用所有的计划任务……");
            foreach (ISchedule aSchedule in from r in Schedules where !r.IsStart select r)
            {
                aSchedule.Start();
            }
        }
       
        public void StopAllSchedules()
        {
            L("停用所有的计划任务……");
            foreach (ISchedule aSchedule in from r in Schedules where r.IsStart select r)
            {
                aSchedule.Stop();
            }
        }

        protected void DispatchThread(object aParameter)
        {
            if (!(aParameter is ISchedule aSchedule)) return;
            try
            {
                aSchedule.OnDispatch(_Content); // Schedule的OnDispatch应负责对IsDisptching状态进行设置。
            }
            catch (ThreadAbortException)
            {
                Thread.ResetAbort();
            }
            catch (Exception ex)
            {
                E(ex, $"Dispatch {aSchedule.Description}");
            }
        }

        private void OnDispatch_Tick(object sender, EventArgs e)
        {
            try
            {
                // 依次检查每一个计划任务，对到达调度时间的计划任务，创建执行线程，调度执行计划任务。
                List<ISchedule> aSchedules = (from r in Schedules where r.IsStart && DateTime.Now >= r.NextDispatchTime && !r.IsDispatching select r).ToList();
                foreach (ISchedule aSchedule in aSchedules)
                {
                    aSchedule.NextDispatchTime = DateTime.Now + aSchedule.Interval;
                    Thread aThread = new Thread(new ParameterizedThreadStart(this.DispatchThread))
                    {
                        IsBackground = true
                    };
                    aThread.Start(aSchedule);
                }
            }
            catch (Exception ex)
            {
                E(ex, "Disptch");
            }
        }

        protected readonly DispatcherTimer _Timer;
        protected readonly Dispatcher _Dispatcher;
        protected readonly object _Content;

        #endregion
    }
}
